using UnityEngine;
using System.Collections;

[RequireComponent(typeof(CharacterController))]
public class EnemyControl : StateBehaviour<EnemyControl>
{
    #region Attributes

    /* Stats */
    public float health = 1.0f;
    public float walkSpeed = 3.0f;
    public float runSpeed = 7.0f;
    public float walkBackwardsSpeed = 2.0f;

    /* Ranges */
    public float viewAngle = 60.0f;
    public float viewRange = 3.0f;
    public float attackRange = 0.5f;
    public float detectionRange = 1.0f;

    /*  Control */
    public Weapon weapon;
    [HideInInspector]
    public bool isTakeDamageEnable = true;
    [HideInInspector]
    public Vector3 moveDirection = Vector3.zero;
    private CharacterController controller;

    /* Times */
    public float waitTimeIdle = 0.0f;
    public float waitTimeAlert = 0.0f;
    public float waitTimeAlertLookDirection = 0.0f;
    public float waitTimeAttack = 0.0f;
    public float waitTimeWaitWalkBackwards = 0.0f;
    public float waitTimeTakeDamage = 0.0f;
    public float waitTimeDie = 0.0f;
    [HideInInspector]
    public float waitTimeEndState;
    [HideInInspector]
    public float waitTimeEndAction;

    /* Waypoints */
    public bool useWaypoints = false;
    public Transform[] waypoints;
    private int currentWaypoint = 0;
    
    /* Helpers */
    private Quaternion maxViewAngle;
    private Quaternion minViewAngle;

    #endregion

    #region Props

    public Transform CurrentWaypoint
    {
        get 
        {
            return (this.currentWaypoint < this.waypoints.Length ?
                    this.waypoints[this.currentWaypoint] : null);
        }
    }

    public bool IsGrounded
    {
        get
        {
            return this.controller.isGrounded;
        }
    }

    #endregion

    #region Methods

    public void Move()
    {
        // Apply Gravity
        this.moveDirection.y -= Constants.GRAVITY * Time.deltaTime;
        // Move
        this.controller.Move(this.moveDirection * Time.deltaTime);
    }

    public void TurnAround()
    {
        this.transform.rotation *= Quaternion.Euler(0, 180, 0);
    }

    public bool IsTargetInViewRange()
    {
        bool result = false;
        RaycastHit hit;

        if (Physics.Raycast(this.transform.position, this.transform.forward, out hit, this.viewRange) &&
            hit.collider.name == Constants.PLAYER_NAME) 
        {
            result = true;
        }
        else if (Physics.Raycast(this.transform.position, this.maxViewAngle * this.transform.forward, out hit, this.viewRange) &&
                 hit.collider.name == Constants.PLAYER_NAME)
        {
            result = true;
        }
        else if (Physics.Raycast(this.transform.position, this.minViewAngle * this.transform.forward, out hit, this.viewRange) &&
                 hit.collider.name == Constants.PLAYER_NAME)
        {
            result = true;
        }
        
        return result;
    }

    public bool IsTargetInAttackRange()
    {
        bool result = false;
        RaycastHit hit;
        
        if (Physics.Raycast(this.transform.position, this.transform.forward, out hit, this.attackRange) &&
            hit.collider.name == Constants.PLAYER_NAME)
        {
            result = true;
        }
        else if (Physics.Raycast(this.transform.position, this.maxViewAngle * this.transform.forward, out hit, this.attackRange) &&
                 hit.collider.name == Constants.PLAYER_NAME)
        {
            result = true;
        }
        else if (Physics.Raycast(this.transform.position, this.minViewAngle * this.transform.forward, out hit, this.attackRange) &&
                 hit.collider.name == Constants.PLAYER_NAME)
        {
            result = true;
        }

        return result;
    }

    public bool IsObstacleInDetectionRange()
    {
        bool result = false;
        RaycastHit hit;

        if (Physics.Raycast(this.transform.position, this.transform.forward, out hit, this.detectionRange) &&
            hit.collider.name != Constants.PLAYER_NAME)
        {
            result = true;
        }

        return result;
    }

    public void NextWaypoint()
    {
        ++this.currentWaypoint;
        if (this.currentWaypoint >= this.waypoints.Length)
            this.currentWaypoint = 0;            
    }

    #endregion

    #region Unity Methods

    void Start()
    {
        this.controller = this.GetComponent<CharacterController>();
        this.State = EnemyIdleState.Instance;
        this.maxViewAngle = Quaternion.Euler(0, 0, this.viewAngle / 2);
        this.minViewAngle = Quaternion.Euler(0, 0, -this.viewAngle / 2);
    }
    public void DoAction(string name, object parameters)
    {
    }
    void OnTriggerEnter(Collider other)
    {
        this.State.OnTriggerState(this, other);
    }

    void OnDrawGizmos()
    {
        Debug.DrawRay(this.transform.position, Quaternion.Euler(0, 0, this.viewAngle/2) * this.transform.forward * this.viewRange, Color.red);
        Debug.DrawRay(this.transform.position, this.transform.forward * this.viewRange, Color.red);
        Debug.DrawRay(this.transform.position, Quaternion.Euler(0, 0, -this.viewAngle/2) * this.transform.forward * this.viewRange, Color.red); 
    }

    #endregion

    #region StateBehaviour

    public override EnemyControl GetBehaviuor()
    {
        return this;
    }

    #endregion
}
